AngularJS コードの構造化
複数人で AngularJS を利用した Web アプリケーションを構築するときに必要なルールをまとめてみました。
( あくまで策定中のルールであり、今後も改変する可能性があります。また、ベストプラクティスを謳うものではありません )
使用 AngularJS のバージョン
- angular.js 1.2.5
- angular-route.js 1.2.5
参考サイト
- Dan Wahlin's Blog | Structuring AngularJS Code
http://weblogs.asp.net/dwahlin/archive/2013/12/01/structuring-angularjs-code.aspx - GitHub | mgechev / angularjs-style-guide / README-ja-jp.md
https://github.com/mgechev/angularjs-style-guide/blob/master/README-ja-jp.md
ナナメ読みした参考書籍
いずれも 1.2 系以前のバージョンで書かれていますが、基本的なことを抑えるスタートアップ書籍としては十分かと思います。
Application HTML
アプリケーションの基盤となる HTML です。 HTML タグの ng-app 属性にアプリケーション名を設定して、アプリケーションとして展開される領域に単一の ng-view 属性を設定します。アプリケーション内の画面遷移や UI の表示切替といった機能は、angular-route.js のサービスである $routeProvider を使用します。ディレクトリ構造はアプリケーションの要件によって変化すると思われるので、当記事では割愛します。
index.html
<!DOCTYPE html> <html ng-app='testApp'> <head> <script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.js'></script> <script src='//ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.js'></script> <script src='app/app.js'></script> <script src='service/hogeService.js'></script> <script src='filter/hogeFilter.js'></script> <script src='controller/HogeController.js'></script> <script src='controller/FugaController.js'></script> <script src='directives/cmHogeDirective.js'></script> <link rel='stylesheet' href='view/styles.css' /> <title>Structuring AngularJS Code</title> </head> <body> <header><h1>Sample</h1></header> <div ng-view></div> <footer></footer> </body> </html>
Application JS
アプリケーション本体の JS です。ネームスペースを示すグローバルオブジェクトを用意して、任意のプロパティにアプリケーションのモジュールの参照を代入します。モジュールの作成には angular#module メソッドを使用します。前述の $routeProvider を使用して、各画面の URL に対する View(templeteUrl) と Controller(controller) のペアを定義します。
app.js
'use strict'; var ns = ns || {}; ns.App = angular.module('testApp', ['ngRoute'], function($routeProvider) { $routeProvider .when('/hoge/',{ controller: 'HogeController', templateUrl: 'view/HogeView.html' }) .when('/fuga/',{ controller: 'FugaController', templateUrl: 'view/FugaView.html' }); });
匿名関数の引数 $routeProvider の名前を変更すると動作しなくなるので、minify するときには注意する必要があります。( または、このファイルのみ minify の対象から外すのもアリかもしれません )
View(templateUrl)
アプリケーションの外観を構築します。ここにはプレーンな HTML タグや AngularJS のカスタム Directive を配置します。動的に変わるパラメータは、二重の波括弧で括ったバインディング式を定義して値を渡します。この View 内部で AngularJS の $filter を用いたフィルタリング処理を実装することができますが、複数回実行される現象を確認しているため、原則 Controller で使用ことを掟とします。
HogeView.html
<h2>{{title}}</h2> <div data-value="{{value}}"></div>
Filter
Contoroller で使用する整形ユーティリティ ( のようなもの? ) です。
以下のファイルは、引数の文字列に対して語尾に "Hoge!!" を付与して返すフィルタです。
hogeFilter.js
(function () { var hogeFilter = function () { return function (value) { return value + " Hoge!!"; }; }; ns.App.filter('hogeFilter', hogeFilter); }());
Controller
先述の View に値を渡したり、サービスを実行したりします。また $inject プロパティを用いて $scope, $filter, 任意のサービスなどの依存性を抽入することにより、IntelliJ IDEA ではコードヒントが有効になり、かつ、何も気にせず minify できるので、以下のような構造を保つことを掟とします。引数 $scope はペアとなる View の参照となるので必須、その他の参照は必要に応じて定義します。
HogeController.js
(function() { var HogeController = function($scope, $filter, hogeService) { $scope.title = $filter('hogeFilter')("Sample 1"); $scope.value = hogeService.getHoge(); }; HogeController.$inject = ['$scope', '$filter', 'hogeService']; ns.App.controller('HogeController', HogeController); }());
Service
任意の通信処理やライブラリの利用などといった特定の処理単位で用意します。似たような機能で Factory が存在しますが、使用せず Service で統一することを掟とします。
hogeService.js
(function () { var hogeService = function($http) { this.getHoge = function() { return 'hogehoge'; }; }; hogeService.$inject = ['$http']; ns.App.service('hogeService', hogeService); }());
Directive
内部で完結した独自ロジックを DOM に紐付けて部品化したいときに使用します。
- 独自の接頭辞を付与する ( 'cmXxxxDirective' の 'cm' )
- View から参照するときは全て小文字で各単語をハイフンで区切る
- Controller 同様、$inject プロパティは任意
- restrict オプションは原則 'A' ( デフォルト )
- link オプション関数の引数 attrs プロパティの値は、Directive を使用している View を制御する Contoroller から与えられる
cmHogeDirective.js
(function () { var cmHogeDirective = function ($window, $timeout) { return { restrict: 'A', scope: { data: '=', label: '@', onClick: '&' }, link: function(scope, ele, attrs) { //TODO:独立した処理 // ex: var hoge = attrs.value; } }; }; cmHogeDirective.$inject = ['$window', '$timeout']; ns.App.directive('cmHogeDirective', cmHogeDirective); }());
cmHogeDirective.js を View から参照するとき
<div cm-hoge-directive data-value="{{value}}"></div>
命名規則
- View, Controller はアッパーキャメルケース
- 上記以外はローワーキャメルケース